﻿using System;
using System.Linq;
using System.ServiceProcess;

namespace CProcess.Services
{
    class WindowsServices
    {
        private const char Separator = ';';
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// Start a windows service
        /// </summary>
        /// <param name="serviceName">Service Name</param>
        /// <param name="timeoutMilliseconds">Wait time until service start running to proceed</param>
        public static void StartService(string serviceName, int timeoutMilliseconds)
        {
            var service = new ServiceController(serviceName);
            try
            {
                var timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);

                service.Start();
                service.WaitForStatus(ServiceControllerStatus.Running, timeout);
            }
            catch(Exception e)
            {                   
                log.Fatal(e.Message);
                log.Fatal(e);
            }
        }

        /// <summary>
        /// Stop a windows service
        /// </summary>
        /// <param name="serviceName"></param>
        /// <param name="timeoutMilliseconds">Wait time until service stop running to proceed</param>
        public static void StopService(string serviceName, int timeoutMilliseconds)
        {
            var service = new ServiceController(serviceName);
            try
            {
                var timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);

                service.Stop();
                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
            }
            catch (Exception e)
            {
                log.Fatal(e.Message);
                log.Fatal(e);
            }
        }

        /// <summary>
        /// Restart a windows service
        /// </summary>
        /// <param name="serviceName"></param>
        /// <param name="timeoutMilliseconds">Wait time until service restart to proceed</param>
        public static void RestartService(string serviceName, int timeoutMilliseconds)
        {
            var service = new ServiceController(serviceName);
            try
            {
                var millisec1 = Environment.TickCount;                
                var timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);

                service.Stop();
                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);

                // count the rest of the timeout
                int millisec2 = Environment.TickCount;
                timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds - (millisec2 - millisec1));

                service.Start();
                service.WaitForStatus(ServiceControllerStatus.Running, timeout);
            }
            catch (Exception e)
            {
                log.Fatal(e.Message);
                log.Fatal(e);
            }
        }

        public static ServiceControllerStatus ServiceStatus(string serviceName)
        {
            var service = new ServiceController(serviceName);
            try
            {
                var status = service.Status;
                return status;
            }
            catch (Exception e)
            {
                log.Fatal(e.Message);
                log.Fatal(e);
            }
            return 0;
        }

        /// <summary>
        /// Stop windows service or services
        /// </summary>
        /// <param name="serviceName"></param>
        /// <example>ServiceName1;ServiceName1</example>
        public static void Stop(string serviceName)
        {            
            if (serviceName.Contains(Separator.ToString()))
            {
                var services = serviceName.Split(Separator);
                foreach (var service in services.Where(service => WindowsServices.ServiceStatus(service) == ServiceControllerStatus.Running))
                {
                    WindowsServices.StopService(service, 10000);
                    log.Info(String.Format("Stopping service {1}...({0})", WindowsServices.ServiceStatus(service), service));
                }
            }
            else if (WindowsServices.ServiceStatus(serviceName) == ServiceControllerStatus.Running)
            {
                WindowsServices.StopService(serviceName, 10000);
                log.Info(String.Format("Stopping service {1}...({0})", WindowsServices.ServiceStatus(serviceName), serviceName));
            }
        }

        /// <summary>
        /// Start a windows service or services
        /// </summary>
        /// <param name="serviceName"></param>
        /// <example>ServiceName1;ServiceName1</example>
        public static void Start(string serviceName)
        {
            if (serviceName.Contains(Separator.ToString()))
            {
                var services = serviceName.Split(Separator);
                foreach (var service in services.Where(service => WindowsServices.ServiceStatus(service) == ServiceControllerStatus.Stopped))
                {
                    WindowsServices.StartService(service, 10000);
                    log.Info(String.Format("Starting service {1}...({0})", WindowsServices.ServiceStatus(service), service));
                }
            }
            else if (WindowsServices.ServiceStatus(serviceName) == ServiceControllerStatus.Stopped)
            {
                WindowsServices.StartService(serviceName, 10000);
                log.Info(String.Format("Starting service {1}...({0})", WindowsServices.ServiceStatus(serviceName), serviceName));
            }
        }
    
    }
}
